package com.hmall.item.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.common.domain.PageDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;

import com.hmall.item.domain.dto.ItemDTO;
import com.hmall.item.domain.dto.OrderDetailDTO;
import com.hmall.item.domain.po.Item;
import com.hmall.item.domain.po.ItemDoc;
import com.hmall.item.domain.query.ItemPageQuery;
import com.hmall.item.mapper.ItemMapper;
import com.hmall.item.service.IItemService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * 商品表 服务实现类
 * </p>
 *
 * @author 虎哥
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements IItemService {
    private final RestHighLevelClient client;

    @Override
    @Transactional
    public void deductStock(List<OrderDetailDTO> items) {
        String sqlStatement = "com.hmall.item.mapper.ItemMapper.updateStock";
        boolean r = false;
        try {
            r = executeBatch(items, (sqlSession, entity) -> sqlSession.update(sqlStatement, entity));
        } catch (Exception e) {
            throw new BizIllegalException("更新库存异常，可能是库存不足!", e);
        }
        if (!r) {
            throw new BizIllegalException("库存不足！");
        }
    }

    @Override
    public List<ItemDTO> queryItemByIds(Collection<Long> ids) {
        return BeanUtils.copyList(listByIds(ids), ItemDTO.class);
    }

    //复合查询es数据
    public PageDTO<ItemDTO> search(ItemPageQuery query) throws IOException {
        //1.创建请求对象
        SearchRequest request = new SearchRequest("items");
        //2.准备请求参数
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        if (StrUtil.isNotBlank(query.getKey())) {
            bool.must(QueryBuilders.matchQuery("name", query.getKey()));
        }
        if(StrUtil.isNotBlank(query.getBrand())){
            bool.filter(QueryBuilders.termQuery("brand", query.getBrand()));
        }
        if(StrUtil.isNotBlank(query.getCategory())){
            bool.filter(QueryBuilders.termQuery("category", query.getCategory()));
        }
        bool.filter(QueryBuilders.termQuery("status", 1));
        if(query.getMaxPrice() != null){
            bool.filter(QueryBuilders.rangeQuery("price").lte(query.getMaxPrice()).gte(query.getMinPrice()));
        }
        if (query.getPageNo()!=null && query.getPageSize()!=null){
            request.source().from(query.from()).size(query.getPageSize());
        }
        if(query.getIsAsc()){
            request.source().sort("update_time", SortOrder.ASC);
        }
        //3，发送请求

            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            // 4.处理响应结果
            return handlerSearchResponse(response,query);
        }
    //利用桶进行分组
    public PageDTO<ItemDTO> searchByAgg(ItemPageQuery query) throws IOException {
        //1.创建请求对象
        SearchRequest request = new SearchRequest("items");
        //2.准备请求参数
        if (!query.getCategory().isBlank()) {
            request.source().aggregation(
                    AggregationBuilders.terms("cate_agg")
                            .field("category")
                            .size(20)
            );
        }
        if (!query.getBrand().isBlank()) {
            request.source().aggregation(
                    AggregationBuilders.terms("brand_agg")
                            .field("brand")
                            .size(20)
            );
        }
        //3.发送请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //4.解析请求
         return handlerSearchResponseForAgg(response,query);
    }
    //桶聚合解析
    private PageDTO<ItemDTO> handlerSearchResponseForAgg(SearchResponse response, ItemPageQuery query) {
        if (response == null) {
            return null;
        }
        //解析桶
        Aggregations aggregations = response.getAggregations();
        Terms cateAgg = aggregations.get("cate_agg");
        List<? extends Terms.Bucket> buckets = cateAgg.getBuckets();
        for (Terms.Bucket bucket : buckets) {
            String keyAsString = bucket.getKeyAsString();
            log.info("keyAsString:{}",keyAsString);
            // TODO 创建一个方法，根据商品的分类或者品牌查询商品
            //思路：将keyAsString封装为一个数组或者集合，里面都是各种分类或者品牌
            searchByCategory(keyAsString)
        }
        return null;
    }




    private PageDTO<ItemDTO> handlerSearchResponse(SearchResponse response, ItemPageQuery query) {
        if (response == null) {
            return null;
        }
        List<ItemDoc> list = new ArrayList<>();
        SearchHits responseHits = response.getHits();
        SearchHit[] hits = responseHits.getHits();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            ItemDoc itemDoc = JSONUtil.toBean(sourceAsString, ItemDoc.class);
            list.add(itemDoc);
        }
        long value = responseHits.getTotalHits().value;
        List<ItemDTO> itemDTOS = BeanUtil.copyToList(list, ItemDTO.class);
        Long pageSize = Long.valueOf(query.getPageSize());
        return new PageDTO<>(value,pageSize, itemDTOS);
    }
}
